# -*- coding: utf-8 -*-
'''
version: 08/02/2012

@authors:       Carlos Sancho nº12064
                Armando Gomes nº12067

Descrição:      Trabalho realizado no âmbito da Unidade Curricular de
                Conceitos de Programação para a Segurança 
                Módulo de Python.

Docente:        José Jasnau Caeiro


Tempos Médios de Execução:
    Nºs Gerados     Tempo
    1 000 000:      2.316s
    10 000 000:     23.824s
    100 000 000:    225.662s

CPU: Intel® Core™2 Duo Processor E8500 
    (6M Cache, 3.16 GHz, 1333 MHz FSB)
'''

import time
import random
import sys


class PyRNG:

    def __init__(self, number_runs, verbose = False):
        self.number_runs = number_runs
        self.verbose = verbose
        pass
    

    def populate(self):
        '''
        This function populates a new list with specific limits. In this
        case, it populates the table with the same amount of different
        digits.
        '''
        table = []
        control = [0 for x in range(10)]
        i = 0
        while i < 1000:
            y = random.randint(0,9)
            if(control[y] < 100):
                table.append(y)
                control[y] += 1
                i += 1
                pass
            pass
        return table
    
    
    def swap(self, table, total, p):
        '''
        This function swaps the values on the table accordingly to the
        specified conditions
        '''
        if(p < total):
            z = table[p + (1000 - total)]
            table[0], table[p + (1000 - total)] = table[p + (1000 - total)], table[0]  
        else:
            z = table[0]
        return z
    
    
    def run(self):
        '''
        This function executes the generation of N (this value is given by the argument number_runs) pseudo random numbers.
        '''
        table = self.populate()
        t1 = time.clock()
        p = random.randint(0, 999)
            
        for x in range(self.number_runs):
            z1 = z2 = z3 = z4 = 0    
        
            z1 = self.swap(table, 1000, p)
            z2 = self.swap(table, 999, p)
            z3 = self.swap(table, 998, p)
            z4 = self.swap(table, 997, p)
    
            n = (z1 << 12) | (z2 << 8) | (z3 << 4) | z4
        
            if(self.verbose == True):
                print str(x) + " => " + str(n) + "   ||   p => " +  str(p)
            
            if(p >= 999):
                p = random.randint(0, 998)
            else:
                p = z1 * 100 + z2 * 10 + z3
    
            pass
    
        t2 = time.clock()
    
        print "Time Elasped: " + str(t2-t1)
        pass
